package com.sky.loveshop.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.sky.loveshop.config.DataConfig;
import com.sky.loveshop.entity.OrderDetail;
import com.sky.loveshop.entity.OrderInfo;
import com.sky.loveshop.entity.Sku;
import com.sky.loveshop.entity.aliPay.NotifyMessage;
import com.sky.loveshop.entity.aliPay.OrderDetailRequest;
import com.sky.loveshop.entity.aliPay.OrderRequest;
import com.sky.loveshop.entity.aliPay.PreCreatResponse;
import com.sky.loveshop.entity.exception.BizException;
import com.sky.loveshop.entity.exception.BizExceptionEnum;
import com.sky.loveshop.entity.qo.StockParam;
import com.sky.loveshop.entity.vo.SkuVO;
import com.sky.loveshop.service.*;
import com.sky.loveshop.utils.OrderUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author xcy
 * @version V1.0
 * @description
 * @date 2024/9/1 11:21
 */
@Slf4j
@Service
public class AliPayServiceImpl implements AliPayService {

    @Resource
    private DataConfig dataConfig;
    @Resource
    private AlipayClient alipayClient;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private SkuService skuService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private IotService iotService;

    private final ReentrantLock lock = new ReentrantLock();


    @Override
    public void testOrderPay(Map<String, Object> param, HttpServletResponse response) throws IOException {

        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderNo(OrderUtils.generateOrderNumber());
        orderInfo.setTotalAmount(new BigDecimal(1));
        orderInfo.setSubject("毓婷(A101)");

        orderInfo.setOrderStatus(0);
        orderInfo.setCreateTime(new Date());
        //orderInfo.setUserId();
        orderInfoService.addOrderInfo(orderInfo);

        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest(); //创建API对应的request
        alipayRequest.setReturnUrl(dataConfig.getZfbReturnUrl());
        alipayRequest.setNotifyUrl(dataConfig.getZfbNotifyUrl()); //在公共参数中设置回跳和通知地址
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("out_trade_no", orderInfo.getOrderNo());
        jsonObject.put("total_amount", orderInfo.getTotalAmount());
        jsonObject.put("subject", orderInfo.getSubject());
        alipayRequest.setBizContent(jsonObject.toString()); //填充业务参数
        String form = "";
        try {
            form = alipayClient.pageExecute(alipayRequest).getBody();  //调用SDK生成表单
            response.setContentType("text/html;charset=" + "UTF-8");
            response.getWriter().write(form); //直接将完整的表单html输出到页面
            response.getWriter().flush();
            response.getWriter().close();
            log.info("拉取支付表单页面结果 = " + JSONObject.toJSONString(form));
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String orderPayNotify(HttpServletRequest request) {

        String result = "fail";

        NotifyMessage msg = null;

        // 为了防止恶意非法的请求来伪造异步回调通知，需要对入参进行验签
        // https://opendocs.alipay.com/support/01raw4?pathHash=fb66d8bb
        // 入参验签通过则返回"success"
        // 入参验签失败则返回 非 "success" 即: "fail"

        String tradeStatus = request.getParameter("trade_status");
        if (("TRADE_SUCCESS").equals(tradeStatus)) {
            Map<String, String[]> parameterMap = request.getParameterMap();

            String notify_times = parameterMap.get("notify_time")[0];
            String notify_type = parameterMap.get("notify_type")[0];
            String notify_id = parameterMap.get("notify_id")[0];
            String app_id = parameterMap.get("app_id")[0];
            String charset = parameterMap.get("charset")[0];
            String version = parameterMap.get("version")[0];
            String sign_type = parameterMap.get("sign_type")[0];
            String sign = parameterMap.get("sign")[0];
            String trade_no = parameterMap.get("trade_no")[0];
            String out_trade_no = parameterMap.get("out_trade_no")[0];
            //String out_biz_no = parameterMap.get("out_biz_no")[0];
            //String buyer_id = parameterMap.get("buyer_id")[0];
            //String buyer_logon_id = parameterMap.get("buyer_logon_id")[0];
            //String seller_id = parameterMap.get("seller_id")[0];
            //String seller_email = parameterMap.get("seller_email")[0];
            String trade_status = parameterMap.get("trade_status")[0];
            //String total_amount = parameterMap.get("total_amount")[0];
            //String receipt_amount = parameterMap.get("receipt_amount")[0];
            //String invoice_amount = parameterMap.get("invoice_amount")[0];
            //String buyer_pay_amount = parameterMap.get("buyer_pay_amount")[0];
            //String point_amount = parameterMap.get("point_amount")[0];
            //String refund_fee = parameterMap.get("refund_fee")[0];
            //String subject = parameterMap.get("subject")[0];
            //String body = parameterMap.get("body")[0];
            //String gmt_create = parameterMap.get("gmt_create")[0];
            //String gmt_payment = parameterMap.get("gmt_payment")[0];
            //String gmt_refund = parameterMap.get("gmt_refund")[0];
            //String gmt_close = parameterMap.get("gmt_close")[0];
            //String fund_bill_list = parameterMap.get("fund_bill_list")[0];
            //String passback_params = parameterMap.get("passback_params")[0];
            //String voucher_detail_list = parameterMap.get("voucher_detail_zist")[0];

            msg = new NotifyMessage();
            msg.setTrade_status(trade_status);
            //msg.setTotal_amount(total_amount);
            msg.setTrade_no(trade_no);
            msg.setOut_trade_no(out_trade_no);

            log.info("orderPayNotifyCallBack 异步回调监听到订单消息 {}", JSONUtil.toJsonStr(msg));
        }

        // 支付宝回调服务器可能是多台，会并发的发送异步回调信息到此接口，为了防止这个接口被多次重复执行，这里加个锁，保证同一时间只能一个线程能执行下面逻辑
        if (lock.tryLock()) {
            try {
                // 处理重复通知
                // 接口的幂等性 无论此异步接口调用多少此 下面的逻辑只会执行一次，保证不会插入多条支付信息，不会多次更新订单状态
                OrderInfo orderInfoByOrderNo = orderInfoService.getOrderInfoByOrderNo(msg.getOut_trade_no());
                if (0 != orderInfoByOrderNo.getOrderStatus()) {
                    log.error("此支付宝订单状态不是未支付,不应该进入此逻辑!(幂等性处理) orderInfo={}", JSONUtil.toJsonStr(orderInfoByOrderNo));
                }

                // 更新订单状态
                orderInfoService.updateOrderInfoByOutTradeNo(msg);

                // TODO 插入支付信息
                // payment_info 表插入一条记录

                // 扣减库存
                List<OrderDetail> orderDetails = orderDetailService.getDetailListByOrderId(orderInfoByOrderNo.getId());
                for (OrderDetail o : orderDetails) {
                    StockParam param = new StockParam();
                    param.setUserId(9999);
                    param.setType(0);
                    param.setNum(o.getNum());
                    param.setSkuId(o.getSkuId());
                    skuService.changeStockNum(param);
                }

                // 下发开门指令
                try {
                    String s = iotService.openDoorAfterPay(orderInfoByOrderNo.getShopId());
                    log.info("openDoorAfterPay 支付成功后开门成功  shopId:{} result:{}", orderInfoByOrderNo.getShopId(), s);
                } catch (Exception e) {
                    log.error("openDoorAfterPay 支付成功后开门失败 shopId:{}", orderInfoByOrderNo.getShopId(), e);
                }

                result = "success";
            } catch (Exception e) {
                log.error("orderPayNotifyError 支付宝异步回调异常", e);
                result = "fail";
                e.printStackTrace();
            } finally {
                // 最终要释放锁
                lock.unlock();
            }
        }
        return result;
    }


    @Override
    public PreCreatResponse preCreatRequest() {
        return generateOrderQrCode("1", "IPhone(A101)", 1);
    }

    @Override
    public String aliPayTradeQuery(String outTradeNo) {

        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        request.setBizModel(model);
        try {
            AlipayTradeQueryResponse response = alipayClient.certificateExecute(request);
            log.info("aliPayTradeQueryResult 查询到订单信息 {} = {}", outTradeNo, JSONUtil.toJsonStr(response.getBody()));
            if (response.isSuccess()) {
                return JSONUtil.toJsonStr(response.getBody());
            } else {
                return outTradeNo + "没找到";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";

    }

    /**
     * 统一收单交易关闭接口
     * https://opendocs.alipay.com/open/59c63968_alipay.trade.close?pathHash=e2bddcee
     *
     * @param orderNo 商户订单号(我方系统内的)
     */
    @Override
    public Integer aliPayTradeClose(String orderNo) {
        AlipayTradeCloseRequest closeRequest = new AlipayTradeCloseRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderNo);
        closeRequest.setBizContent(bizContent.toString());
        AlipayTradeCloseResponse response;
        try {
            response = alipayClient.certificateExecute(closeRequest);
            if (response.isSuccess()) {
                log.info("aliPayTradeClose 支付宝订单关闭成功 orderNo={}", orderNo);
            } else {
                // 情况1：订单在支付宝侧并没有创建，即"交易不存在"
                // 情况2：关闭过程中异常报错
                log.info("aliPayTradeClose 支付宝订单关闭失败 orderNo={}", orderNo);
            }
        } catch (Exception e) {
            log.error("aliPayTradeCloseError 支付宝支付订单关闭异常", e);
            e.printStackTrace();
        }

        // 更新订单状态的逻辑
        OrderInfo orderInfo = orderInfoService.getOrderInfoByOrderNo(orderNo);
        orderInfo.setOrderStatus(3);
        orderInfo.setUpdateTime(new Date());
        orderInfoService.updateOrderStatus(orderInfo);
        return 1;
    }

    @Override
    public Integer aliPayTradeQueryOrderStatus(String orderNo) {
        OrderInfo orderInfo = orderInfoService.getOrderInfoByOrderNo(orderNo);
        return orderInfo.getOrderStatus();
    }

    @Override
    @Transactional
    public PreCreatResponse preCreatOrderAndDetail(OrderRequest orderRequest) throws BizException {

        // 根据skuId查询每一件的商品信息并计算总价格
        List<OrderDetailRequest> orderDetailRequestList = orderRequest.getOrderDetailRequestList();
        List<Integer> skuIds = orderDetailRequestList.stream().map(OrderDetailRequest::getSkuId).collect(Collectors.toList());

        List<SkuVO> skuListByIds = skuService.getSkuListByIds(skuIds);
        // 获取门店信息
        List<Integer> shopIds = skuListByIds.stream().map(Sku::getShopId).distinct().collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(shopIds) && shopIds.size() > 1) {
            throw new BizException(BizExceptionEnum.SKU_NOT_BELONG_ONE_SHOP_ERROR);
        }
        Integer shopId = shopIds.get(0);
        // (skuId:info)
        Map<Integer, SkuVO> skuIdInfoMap = skuListByIds.stream().collect(Collectors.toMap(Sku::getId, Function.identity()));
        // (skuId:salesPrice)
        Map<Integer, BigDecimal> skuIdSalePriceMap = skuListByIds.stream().collect(Collectors.toMap(Sku::getId, Sku::getSalesPrice));
        // (skuId:num)
        Map<Integer, Integer> skuIdNumberMap = orderDetailRequestList.stream().collect(Collectors.toMap(OrderDetailRequest::getSkuId, OrderDetailRequest::getNumber));

        // 提前判断一下每种skuId对应的商品的库存数量够不够
        checkStockNum(skuIdSalePriceMap, skuIdNumberMap);

        // 计算总价格
        String allTotalMoney = calcAllTotalMoney(skuIdNumberMap, skuIdSalePriceMap);
        if (!orderRequest.getTotalAmount().equals(allTotalMoney)) {
            throw new BizException(BizExceptionEnum.TOTAL_MONEY_IS_NOT_MATCH);
        }

        // 生成订单标题(256字符以内)
        String subjectName = assembleSubjectName(skuIdInfoMap, skuIdNumberMap);
        PreCreatResponse preCreatResponse = generateOrderQrCode(allTotalMoney, subjectName, shopId);
        // 新增订单详情数据
        insertOrderDetails(preCreatResponse.getOrderId(), orderDetailRequestList, skuIdInfoMap);
        return preCreatResponse;
    }


    /**
     * 新增订单详情数据
     *
     * @param orderId 主订单id（上一步生成的）
     */
    private void insertOrderDetails(Integer orderId, List<OrderDetailRequest> detailList, Map<Integer, SkuVO> skuIdInfoMap) {

        List orderDetailList = new ArrayList<OrderDetail>();
        for (OrderDetailRequest d : detailList) {

            Integer skuId = d.getSkuId();

            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setSkuId(skuId);
            orderDetail.setProductId(skuIdInfoMap.get(skuId).getProductId());
            orderDetail.setProductName(skuIdInfoMap.get(skuId).getProductName());
            orderDetail.setNum(d.getNumber());
            orderDetail.setPrice(skuIdInfoMap.get(skuId).getSalesPrice());
            orderDetail.setShelfId(skuIdInfoMap.get(skuId).getShelfId());
            orderDetail.setShelfNo(skuIdInfoMap.get(skuId).getShelfName());
            orderDetail.setShopId(skuIdInfoMap.get(skuId).getShopId());
            orderDetail.setShopName(skuIdInfoMap.get(skuId).getShopName());
            orderDetail.setBarCode(skuIdInfoMap.get(skuId).getBarCode());
            orderDetail.setCreateTime(new Date());
            orderDetailList.add(orderDetail);
        }
        orderDetailService.batchInOrderDetail(orderDetailList);
    }

    /**
     * 生成支付宝订单二维码
     *
     * @param allTotalMoney 订单总金额
     * @param subjectName   订单标题
     * @param shopId        商店id
     * @return
     */
    private PreCreatResponse generateOrderQrCode(String allTotalMoney, String subjectName, Integer shopId) {
        PreCreatResponse preCreatResponse = new PreCreatResponse();
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(OrderUtils.generateOrderNumber());
        model.setTotalAmount(allTotalMoney);
        model.setSubject(subjectName);
        request.setBizModel(model);
        request.setReturnUrl(dataConfig.getZfbReturnUrl());
        request.setNotifyUrl(dataConfig.getZfbNotifyUrl());

        try {
            AlipayTradePrecreateResponse response = alipayClient.certificateExecute(request);
            log.info("generateOrderQrCode 当面付生成用户扫商家二维码 {}", response.getBody());
            if (response.isSuccess()) {
                String qrCode = response.getQrCode();
                String outTradeNo = response.getOutTradeNo();
                String code = response.getCode();
                String msg = response.getMsg();
                log.info("generateOrderQrCodeSuccess 调用成功 qrCode = {}; outTradeNo = {}; code = {}; msg={}", qrCode, outTradeNo, code, msg);
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setOrderNo(model.getOutTradeNo());
                orderInfo.setShopId(shopId);
                orderInfo.setQrCode(qrCode);
                orderInfo.setSubject(model.getSubject());
                orderInfo.setTotalAmount(new BigDecimal(allTotalMoney));
                orderInfo.setCreateTime(new Date());
                orderInfo.setOrderStatus(0);
                // 新增订单主数据
                orderInfoService.addOrderInfo(orderInfo);

                preCreatResponse.setOrderId(orderInfo.getId());
                preCreatResponse.setQrCode(qrCode);
                preCreatResponse.setOrderNo(outTradeNo);
                return preCreatResponse;
            } else {
                log.info("调用失败");
            }
        } catch (Exception e) {
            log.error("preCreatRequestError 当面付生成用户扫商家二维码失败", e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断一下每种skuId对应的商品的库存数量够不够
     *
     * @param skuIdSalePriceMap
     * @param skuIdNumberMap
     */
    private void checkStockNum(Map<Integer, BigDecimal> skuIdSalePriceMap, Map<Integer, Integer> skuIdNumberMap) {
        //TODO


    }

    /**
     * 计算订单总价格
     *
     * @param skuIdNumberMap
     * @param skuIdSalePriceMap
     * @return
     */
    private String calcAllTotalMoney(Map<Integer, Integer> skuIdNumberMap, Map<Integer, BigDecimal> skuIdSalePriceMap) {
        BigDecimal allTotalMoney = BigDecimal.ZERO;
        for (Integer key : skuIdNumberMap.keySet()) {
            BigDecimal salesPrice = skuIdSalePriceMap.get(key);
            BigDecimal num = BigDecimal.valueOf(skuIdNumberMap.get(key).longValue());
            BigDecimal totalMoney = salesPrice.multiply(num);
            allTotalMoney = allTotalMoney.add(totalMoney);
        }
        return allTotalMoney.toString();
    }

    /**
     * 组装商品名称
     *
     * @param skuIdInfoMap
     * @param skuIdNumberMap
     * @return
     */
    private String assembleSubjectName(Map<Integer, SkuVO> skuIdInfoMap, Map<Integer, Integer> skuIdNumberMap) {
        String subjectName = "";
        for (Integer skuId1 : skuIdNumberMap.keySet()) {
            for (Integer skuId2 : skuIdInfoMap.keySet()) {
                if (skuId1.equals(skuId2)) {
                    SkuVO skuVO = skuIdInfoMap.get(skuId2);
                    Integer num = skuIdNumberMap.get(skuId2);
                    subjectName = subjectName + skuVO.getProductName() + "-" + num + "个 ";
                }
            }
        }
        // 支付宝订单订单标题长度最大位256,超长用...表示
        String truncatedString = (subjectName.length() > 256) ? subjectName.substring(0, 253) + "..." : subjectName;
        return truncatedString;
    }
}
